package com.cinc.ebc.quote.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cinc.ebc.quote.feeBase.entity.QuoteFeeBase;
import com.cinc.ebc.quote.feeBase.mapper.QuoteFeeBaseMapper;
import com.cinc.ebc.quote.parts.entity.QuoteParts;
import com.cinc.ebc.quote.parts.mapper.QuotePartsMapper;
import com.cinc.ebc.quote.product.entity.QuoteProduct;
import com.cinc.ebc.quote.product.entity.QuoteProductDetail;
import com.cinc.ebc.quote.product.entity.QuoteProductFee;
import com.cinc.ebc.quote.product.mapper.QuoteProductDetailMapper;
import com.cinc.ebc.quote.product.mapper.QuoteProductFeeMapper;
import com.cinc.ebc.quote.product.mapper.QuoteProductMapper;
import com.cinc.ebc.quote.product.model.QuoteProductModel;
import com.cinc.ebc.quote.product.model.QuoteProjectCustomerModel;
import com.cinc.ebc.quote.product.service.IQuoteProductService;
import com.cinc.ebc.quote.product.vo.QuoteProductRequestPage;
import com.cinc.ebc.quote.productClass.entity.QuoteProductClass;
import com.cinc.ebc.quote.productClass.mapper.QuoteProductClassMapper;
import com.cinc.ebc.quote.project.entity.QuoteProject;
import com.cinc.ebc.quote.project.mapper.QuoteProjectMapper;
import com.cinc.mdm.modules.codeRule.service.IMdmCodeRuleService;
import com.cinc.mdm.modules.customer.entity.MdmCustomer;
import com.cinc.mdm.modules.customer.mapper.MdmCustomerMapper;
import com.cinc.mdm.modules.customerContacts.entity.MdmCustomerContacts;
import com.cinc.mdm.modules.customerContacts.mapper.MdmCustomerContactsMapper;
import com.cinc.mdm.modules.material.entity.MdmMaterial;
import com.cinc.mdm.modules.material.mapper.MdmMaterialMapper;
import com.cinc.mdm.modules.materialClass.entity.MdmMaterialClass;
import com.cinc.mdm.modules.materialClass.mapper.MdmMaterialClassMapper;
import com.cinc.mdm.modules.materialCodeRule.service.IMdmMaterialCodeRuleService;
import com.cinc.mdm.modules.materialType.entity.MdmMaterialType;
import com.cinc.mdm.modules.materialType.mapper.MdmMaterialTypeMapper;
import com.cinc.mdm.modules.unit.service.IMdmUnitService;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.UUIDGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 报价产品
 * @Author: jeecg-boot
 * @Date: 2023-03-22
 * @Version: V1.0
 */
@Service
public class QuoteProductServiceImpl extends ServiceImpl<QuoteProductMapper, QuoteProduct> implements IQuoteProductService {

    @Autowired
    private QuoteProductMapper quoteProductMapper;
    @Autowired
    private QuoteProductDetailMapper quoteProductDetailMapper;
    @Autowired
    private QuoteProductFeeMapper quoteProductFeeMapper;
    @Autowired
    private QuoteProjectMapper quoteProjectMapper;
    @Autowired
    private QuoteProductClassMapper quoteProductClassMapper;
    @Autowired
    private MdmMaterialMapper mdmMaterialMapper;
    @Autowired
    private IMdmCodeRuleService mdmCodeRuleService;
    @Autowired
    private MdmCustomerMapper mdmCustomerMapper;
    @Autowired
    private MdmCustomerContactsMapper mdmCustomerContactsMapper;
    @Autowired
    private ISysBaseAPI sysBaseAPI;
    @Autowired
    private IMdmUnitService mdmUnitService;
    @Autowired
    private QuotePartsMapper quotePartsMapper;
    @Autowired
    private QuoteFeeBaseMapper quoteFeeBaseMapper;
    @Autowired
    private IMdmMaterialCodeRuleService mdmMaterialCodeRuleService;
    @Autowired
    private MdmMaterialTypeMapper mdmMaterialTypeMapper;
    @Autowired
    private MdmMaterialClassMapper mdmMaterialClassMapper;

    @Override
    @Transactional
    public void saveMain(QuoteProduct quoteProduct, List<QuoteProductDetail> quoteProductDetailList, List<QuoteProductFee> quoteProductFeeList) {
        if (oConvertUtils.isEmpty(quoteProduct.getProjectId())) {
            throw new RuntimeException("项目不能为空");
        }
        quoteProductMapper.insert(quoteProduct);
        // 更新分类价格
        if (oConvertUtils.isNotEmpty(quoteProduct.getProductClassId())) {
            quoteProductClassMapper.updateProductPriceById(quoteProduct.getProductClassId());
            quoteProductClassMapper.updateSumPriceById(quoteProduct.getProductClassId());
        }
        if (quoteProductDetailList != null && quoteProductDetailList.size() > 0) {
            for (QuoteProductDetail entity : quoteProductDetailList) {
                //外键设置
                entity.setMainId(quoteProduct.getId());
                quoteProductDetailMapper.insert(entity);
            }
        }

        if (quoteProductFeeList != null && quoteProductFeeList.size() > 0) {
            for (QuoteProductFee entity : quoteProductFeeList) {
                //外键设置
                entity.setMainId(quoteProduct.getId());
                quoteProductFeeMapper.insert(entity);
            }
        }
        // 更新零部件
        handleQuotePartsAsync(quoteProduct.getId());
    }

    @Override
    @Transactional
    public void updateMain(QuoteProduct quoteProduct, List<QuoteProductDetail> quoteProductDetailList, List<QuoteProductFee> quoteProductFeeList) {

        quoteProductMapper.updateById(quoteProduct);

        // 清单明细处理
        List<String> productDetailNewIdList = quoteProductDetailList.stream().map(QuoteProductDetail::getId).collect(Collectors.toList());
        List<QuoteProductDetail> productDetailOldList = quoteProductDetailMapper.selectByMainId(quoteProduct.getId());
        List<String> productDetailDeleteIdList = productDetailOldList.stream().filter(productDetail -> !productDetailNewIdList.contains(productDetail.getId())).map(QuoteProductDetail::getId).collect(Collectors.toList());
        if (oConvertUtils.listIsNotEmpty(productDetailDeleteIdList)) {
            // 根据零部件下计划数量进行删除校验
            LambdaQueryWrapper<QuoteProductDetail> detailQuery = new LambdaQueryWrapper<>();
            detailQuery.in(QuoteProductDetail::getId, productDetailDeleteIdList);
            List<QuoteProductDetail> detailDeleteList = quoteProductDetailMapper.selectList(detailQuery);
            List<String> materialIdList = new ArrayList<>();
            Map<String, BigDecimal> materialIdAndQty = new HashMap<>();
            for (QuoteProductDetail productDetail : detailDeleteList) {
                if (materialIdAndQty.containsKey(productDetail.getMaterialId())) {
                    BigDecimal tempQty = materialIdAndQty.get(productDetail.getMaterialId()).add(productDetail.getQty());
                    materialIdAndQty.put(productDetail.getMaterialId(), tempQty);
                } else {
                    materialIdAndQty.put(productDetail.getMaterialId(), productDetail.getQty());
                    materialIdList.add(productDetail.getMaterialId());
                }
            }
            LambdaQueryWrapper<QuoteParts> partsQuery = new LambdaQueryWrapper<>();
            partsQuery.eq(QuoteParts::getProjectId, quoteProduct.getProjectId());
            partsQuery.in(QuoteParts::getMaterialId, materialIdList);
            partsQuery.gt(QuoteParts::getPlanQty, 0);
            List<QuoteParts> quotePartsList = quotePartsMapper.selectList(partsQuery);
            QuoteParts findParts = quotePartsList.stream().filter(parts -> parts.getQty().subtract(parts.getPlanQty()).compareTo(materialIdAndQty.get(parts.getMaterialId())) == -1)
                    .findFirst().orElse(null);
            if (findParts != null) {
                throw new RuntimeException(findParts.getMaterialCode() + " 已下计划数量：" + findParts.getPlanQty().toPlainString() + "，不能删除");
            }
            // 删除
            quoteProductDetailMapper.delete(new LambdaQueryWrapper<QuoteProductDetail>().in(QuoteProductDetail::getId, productDetailDeleteIdList));
        }
        // 新增、修改处理
        if (quoteProductDetailList != null && quoteProductDetailList.size() > 0) {
            List<String> idList = quoteProductDetailList.stream().map(QuoteProductDetail::getId).collect(Collectors.toList());
            for (QuoteProductDetail entity : quoteProductDetailList) {
                QuoteProductDetail findProductDetail = productDetailOldList.stream().filter(productDetail -> productDetail.getId().equals(entity.getId())).findFirst().orElse(null);
                if (findProductDetail == null) {
                    // 新增
                    entity.setMainId(quoteProduct.getId());
                    quoteProductDetailMapper.insert(entity);
                } else {
                    // 修改
                    BigDecimal changeQty = findProductDetail.getQty().subtract(entity.getQty());
                    if (changeQty.compareTo(BigDecimal.ZERO) == 1) {
                        // 数量改小，校验零部件
                        LambdaQueryWrapper<QuoteParts> partsQuery = new LambdaQueryWrapper<>();
                        partsQuery.eq(QuoteParts::getProjectId, quoteProduct.getProjectId());
                        partsQuery.eq(QuoteParts::getMaterialId, entity.getMaterialId());
                        partsQuery.gt(QuoteParts::getPlanQty, 0);
                        QuoteParts quoteParts = quotePartsMapper.selectOne(partsQuery);
                        if (quoteParts != null && quoteParts.getQty().subtract(quoteParts.getPlanQty()).compareTo(changeQty) == -1) {
                            throw new RuntimeException(entity.getMaterialCode() + " 已下计划数量：" + quoteParts.getPlanQty().setScale(2, RoundingMode.HALF_UP).toPlainString() + "，修改失败");
                        }
                    }
                    quoteProductDetailMapper.updateById(entity);
                }
            }
        }

        // 费用处理：全删全增
        quoteProductFeeMapper.deleteByMainId(quoteProduct.getId());
        if (quoteProductFeeList != null && quoteProductFeeList.size() > 0) {
            for (QuoteProductFee entity : quoteProductFeeList) {
                //外键设置
                entity.setMainId(quoteProduct.getId());
                quoteProductFeeMapper.insert(entity);
            }
        }
        // 更新零部件
        List<String> materialIdList = new ArrayList<>();
        materialIdList.addAll(quoteProductDetailList.stream().map(QuoteProductDetail::getMaterialId).collect(Collectors.toList()));
        materialIdList.addAll(productDetailOldList.stream().map(QuoteProductDetail::getMaterialId).collect(Collectors.toList()));
        materialIdList = materialIdList.stream().distinct().collect(Collectors.toList());
        handleQuotePartsAsync(quoteProduct.getId(), materialIdList);
    }

    /**
     * 异步更新零部件需求
     *
     * @param quoteProductId
     */
    @Async
    @Override
    public void handleQuotePartsAsync(String quoteProductId) {
        List<QuoteProductDetail> productDetailList = quoteProductDetailMapper.selectByMainId(quoteProductId);
        List<String> materialIdList = productDetailList.stream().map(QuoteProductDetail::getMaterialId).collect(Collectors.toList());
        handleQuotePartsAsync(quoteProductId, materialIdList);
    }

    /**
     * 异步更新零部件需求
     *
     * @param quoteProductId
     * @param materialIdList
     */
    @Async
    @Transactional
    @Override
    public void handleQuotePartsAsync(String quoteProductId, List<String> materialIdList) {
        if (oConvertUtils.listIsEmpty(materialIdList)) {
            return;
        }
        QuoteProduct quoteProduct = quoteProductMapper.selectById(quoteProductId);
        // 新添加的清单明细，先生成零部件需求
        List<QuoteProductDetail> productDetailList = quoteProductDetailMapper.selectPartsAddList(quoteProduct.getProjectId(), materialIdList);
        List<String> materialIdDistinctList = new ArrayList<>();
        for (QuoteProductDetail productDetail : productDetailList) {
            if (materialIdDistinctList.contains(productDetail.getMaterialId())) {
                // 防止清单明细物料重复，导致零部件需求重复添加
                continue;
            }
            QuoteParts quotePartsAdd = new QuoteParts();
            quotePartsAdd.setId(UUIDGenerator.generate());
            quotePartsAdd.setProjectId(quoteProduct.getProjectId());
            quotePartsAdd.setMaterialId(productDetail.getMaterialId());
            quotePartsAdd.setMaterialCode(productDetail.getMaterialCode());
            quotePartsAdd.setMaterialDesc(productDetail.getMaterialDesc());
            quotePartsAdd.setMaterialFactory(productDetail.getMaterialFactory());
            quotePartsAdd.setUnit(productDetail.getUnit());
            quotePartsAdd.setStatus("01");
            quotePartsAdd.setQty(productDetail.getQty());
            quotePartsAdd.setUnitPrice(productDetail.getUnitPrice());
            quotePartsAdd.setSumPrice(productDetail.getSumPrice());
            quotePartsAdd.setCostSumPrice(productDetail.getCostSumPrice());
            quotePartsAdd.setCostUnitPrice(productDetail.getCostUnitPrice());
            quotePartsAdd.setPlanQty(BigDecimal.ZERO);
            quotePartsAdd.setPurQty(BigDecimal.ZERO);
            quotePartsMapper.insert(quotePartsAdd);

            materialIdDistinctList.add(productDetail.getMaterialId());
        }
        // 更新需求数量金额
        quotePartsMapper.autoUpdateParts(quoteProduct.getProjectId(), materialIdList);
        // 删除无效需求
        quotePartsMapper.deleteInvalid(quoteProduct.getProjectId(), materialIdList);
    }

    @Override
    @Transactional
    public void delMain(String id) {
        QuoteProduct quoteProduct = quoteProductMapper.selectById(id);
        List<QuoteProductDetail> productDetailList = quoteProductDetailMapper.selectByMainId(id);
        // 删除
        quoteProductDetailMapper.deleteByMainId(id);
        quoteProductFeeMapper.deleteByMainId(id);
        quoteProductMapper.deleteById(id);
        // 更新零部件需求
        if (oConvertUtils.listIsNotEmpty(productDetailList)) {
            List<String> materialIdList = productDetailList.stream().map(QuoteProductDetail::getMaterialId).collect(Collectors.toList());
            // 更新需求数量金额
            quotePartsMapper.autoUpdateParts(quoteProduct.getProjectId(), materialIdList);
            // 删除无效需求
            quotePartsMapper.deleteInvalid(quoteProduct.getProjectId(), materialIdList);
        }
    }

    @Override
    @Transactional
    public void delBatchMain(Collection<? extends Serializable> idList) {
        for (Serializable id : idList) {
            delMain(id.toString());
        }
    }

    /**
     * 导入数据保存
     *
     * @param quoteProject
     * @param projectCustomerModel
     * @param productClassList
     * @param productList
     * @param productDetailList
     * @param productMaterialList
     * @param productDetailMaterialList
     * @param productFeeList
     */
    @Transactional
    @Override
    public void saveQuoteProductImport(QuoteProject quoteProject, QuoteProjectCustomerModel projectCustomerModel,
                                       List<QuoteProductClass> productClassList, List<QuoteProduct> productList, List<QuoteProductDetail> productDetailList,
                                       List<MdmMaterial> productMaterialList, List<MdmMaterial> productDetailMaterialList, List<QuoteProductFee> productFeeList) {

        LambdaQueryWrapper<QuoteProject> projectQuery = new LambdaQueryWrapper<>();
        projectQuery.eq(QuoteProject::getProjectName, quoteProject.getProjectName());
        int projectCount = quoteProjectMapper.selectCount(projectQuery);
        if (projectCount > 0) {
            throw new RuntimeException("项目已经存在，不能导入");
        }
        // 1. 客户及联系人
        LambdaQueryWrapper<MdmCustomer> customerQuery = new LambdaQueryWrapper<>();
        customerQuery.eq(MdmCustomer::getCustFullName, projectCustomerModel.getCustFullName());
        List<MdmCustomer> customerList = mdmCustomerMapper.selectList(customerQuery);
        MdmCustomer customer = oConvertUtils.listIsEmpty(customerList) ? null : customerList.get(0);
        if (customer == null) {
            // 未找到客户，新增客户
            customer = new MdmCustomer();
            BeanUtils.copyProperties(projectCustomerModel, customer);
            customer.setId(UUIDGenerator.generate());
            mdmCustomerMapper.insert(customer);
        }
        MdmCustomerContacts contacts = null;
        if (oConvertUtils.isNotEmpty(projectCustomerModel.getContactsName())) {
            // 联系人
            LambdaQueryWrapper<MdmCustomerContacts> contactsQuery = new LambdaQueryWrapper<>();
            contactsQuery.eq(MdmCustomerContacts::getCustomerId, customer.getId());
            contactsQuery.eq(MdmCustomerContacts::getName, projectCustomerModel.getContactsName());
            if (oConvertUtils.isNotEmpty(projectCustomerModel.getContactsPhone())) {
                contactsQuery.eq(MdmCustomerContacts::getMobile, projectCustomerModel.getContactsPhone());
            } else {
                contactsQuery.isNull(MdmCustomerContacts::getMobile);
            }
            List<MdmCustomerContacts> contactsList = mdmCustomerContactsMapper.selectList(contactsQuery);
            contacts = oConvertUtils.listIsEmpty(contactsList) ? null : contactsList.get(0);
            if (contacts == null) {
                //新增联系人
                contacts = new MdmCustomerContacts();
                contacts.setId(UUIDGenerator.generate());
                contacts.setCustomerId(customer.getId());
                contacts.setName(projectCustomerModel.getContactsName());
                contacts.setMobile(projectCustomerModel.getContactsPhone());
                mdmCustomerContactsMapper.insert(contacts);
            }
        }

        // 2. 项目
        quoteProject.setProjectNo(mdmCodeRuleService.generateCodeByCodeType("41"));
        if (oConvertUtils.isEmpty(quoteProject.getQuoteNo())) {
            quoteProject.setQuoteNo(mdmCodeRuleService.generateCodeByCodeType("42"));
        }
        quoteProject.setCustomerId(customer.getId());
        if (contacts != null) {
            quoteProject.setContactsId(contacts.getId());
            quoteProject.setContactsPhone(contacts.getMobile());
        }
        quoteProject.setStatus("01");
        quoteProject.setCurrency("RMB");
        quoteProject.setQuoteMan(sysBaseAPI.getUsernameByRealname(quoteProject.getQuoteMan()));
        quoteProject.setQuoteConfirmMan(sysBaseAPI.getUsernameByRealname(quoteProject.getQuoteConfirmMan()));
        quoteProject.setOwner(sysBaseAPI.getUsernameByRealname(quoteProject.getOwner()));
        quoteProject.setOwnerDept(sysBaseAPI.getOrgCodeByUsername(quoteProject.getOwner()));
        quoteProjectMapper.insert(quoteProject);

        // 3. 产品分类
        if(oConvertUtils.listIsNotEmpty(productClassList)){
            for (QuoteProductClass quoteProductClass : productClassList) {
                quoteProductClassMapper.insert(quoteProductClass);
            }
        }

        // 4. 产品物料、产品清单、产品费用
        if (oConvertUtils.listIsNotEmpty(productMaterialList)) {
            Map<String, MdmMaterial> materialIdAndDataOld = new HashMap<>();
            Map<String, MdmMaterial> materialIdAndDataNew = new HashMap<>();
            // 产品物料
            List<String> nameAndSpecList = productMaterialList.stream().map(data -> data.getMaterialName() + data.getMaterialSpec()).collect(Collectors.toList());
            List<MdmMaterial> materialList = mdmMaterialMapper.selectListByNameAndSpec(nameAndSpecList);
            for (MdmMaterial productMaterial : productMaterialList) {
                MdmMaterial findProductMaterial = materialList.stream().filter(data -> data.getMaterialName().equals(productMaterial.getMaterialName())
                        && data.getMaterialSpec().equals(productMaterial.getMaterialSpec())).findFirst().orElse(null);
                if (findProductMaterial == null) {
                    productMaterial.setMaterialCode(getProductMaterialCode(productMaterial));
                    productMaterial.setMaterialUnitCode(mdmUnitService.findUnitCodeByName(productMaterial.getMaterialUnitCode()));
                    mdmMaterialMapper.insert(productMaterial);
                    materialIdAndDataNew.put(productMaterial.getId(), productMaterial);
                } else {
                    materialIdAndDataOld.put(productMaterial.getId(), findProductMaterial);
                }
            }
            // 产品清单
            for (QuoteProduct product : productList) {
                MdmMaterial materialTemp = materialIdAndDataOld.get(product.getMaterialId());
                if (materialTemp != null) {
                    product.setMaterialId(materialTemp.getId());
                    product.setMaterialNo(materialTemp.getMaterialCode());
                    product.setUnit(materialTemp.getMaterialUnitCode());
                } else {
                    materialTemp = materialIdAndDataNew.get(product.getMaterialId());
                    product.setMaterialNo(materialTemp.getMaterialCode());
                    product.setUnit(materialTemp.getMaterialUnitCode());
                }
                product.setCustomerId(customer.getId());
                product.setCurrency("RMB");
                quoteProductMapper.insert(product);
            }
            // 产品费用
            Map<String, String> feeNameAndId = new HashMap<>();
            LambdaQueryWrapper<QuoteFeeBase> feeBaseQuery = new LambdaQueryWrapper<>();
            for (QuoteProductFee productFee : productFeeList) {
                if (feeNameAndId.containsKey(productFee.getFeeId())) {
                    productFee.setFeeId(feeNameAndId.get(productFee.getFeeId()));
                } else {
                    feeBaseQuery.clear();
                    feeBaseQuery.eq(QuoteFeeBase::getFeeName, productFee.getFeeId());
                    List<QuoteFeeBase> feeBaseList = quoteFeeBaseMapper.selectList(feeBaseQuery);
                    if (oConvertUtils.listIsEmpty(feeBaseList)) {
                        QuoteFeeBase quoteFeeBaseAdd = new QuoteFeeBase();
                        quoteFeeBaseAdd.setId(UUIDGenerator.generate());
                        quoteFeeBaseAdd.setFeeName(productFee.getFeeId());
                        quoteFeeBaseAdd.setEnableFlag("1");
                        quoteFeeBaseMapper.insert(quoteFeeBaseAdd);
                        //
                        productFee.setFeeId(quoteFeeBaseAdd.getId());
                        feeNameAndId.put(quoteFeeBaseAdd.getFeeName(), quoteFeeBaseAdd.getId());
                    } else {
                        QuoteFeeBase feeBaseExists = feeBaseList.get(0);
                        productFee.setFeeId(feeBaseExists.getId());
                        feeNameAndId.put(feeBaseExists.getFeeName(), feeBaseExists.getId());
                    }

                }
                quoteProductFeeMapper.insert(productFee);
            }
        }

        // 5. 明细物料、明细清单、零部件统计
        if (oConvertUtils.listIsNotEmpty(productDetailMaterialList)) {
            Map<String, MdmMaterial> materialIdAndDataOld = new HashMap<>();
            Map<String, MdmMaterial> materialIdAndDataNew = new HashMap<>();
            // 明细物料
            List<String> nameSpecFactoryList = productDetailMaterialList.stream().map(data -> data.getMaterialName() + data.getMaterialSpec() + data.getMaterialFactory()).collect(Collectors.toList());
            List<MdmMaterial> materialList = mdmMaterialMapper.selectListByNameSpecFactory(nameSpecFactoryList);
            for (MdmMaterial productDetailMaterial : productDetailMaterialList) {
                MdmMaterial findProductDetailMaterial = materialList.stream().filter(data -> data.getMaterialName().equals(productDetailMaterial.getMaterialName())
                        && data.getMaterialSpec().equals(productDetailMaterial.getMaterialSpec())
                        && data.getMaterialFactory().equals(productDetailMaterial.getMaterialFactory())).findFirst().orElse(null);
                if (findProductDetailMaterial == null) {
                    productDetailMaterial.setMaterialCode(getProductDetailMaterialCode(productDetailMaterial));
                    productDetailMaterial.setMaterialUnitCode(mdmUnitService.findUnitCodeByName(productDetailMaterial.getMaterialUnitCode()));
                    mdmMaterialMapper.insert(productDetailMaterial);
                    materialIdAndDataNew.put(productDetailMaterial.getId(), productDetailMaterial);
                } else {
                    materialIdAndDataOld.put(productDetailMaterial.getId(), findProductDetailMaterial);
                }
            }
            // 明细清单
            List<QuoteParts> partsList = new ArrayList<>();
            List<String> partsMaterialIdList = new ArrayList<>();
            for (QuoteProductDetail productDetail : productDetailList) {
                // 明细清单
                MdmMaterial materialTemp = materialIdAndDataOld.get(productDetail.getMaterialId());
                if (materialTemp != null) {
                    productDetail.setMaterialId(materialTemp.getId());
                    productDetail.setMaterialCode(materialTemp.getMaterialCode());
                    productDetail.setUnit(materialTemp.getMaterialUnitCode());
                    productDetail.setMaterialFactory(materialTemp.getMaterialFactory());
                } else {
                    materialTemp = materialIdAndDataNew.get(productDetail.getMaterialId());
                    productDetail.setMaterialCode(materialTemp.getMaterialCode());
                    productDetail.setUnit(materialTemp.getMaterialUnitCode());
                    productDetail.setMaterialFactory(materialTemp.getMaterialFactory());
                }
                quoteProductDetailMapper.insert(productDetail);
                // 零部件统计
                int partsIndex = partsMaterialIdList.indexOf(productDetail.getMaterialId());
                if (partsIndex >= 0) {
                    QuoteParts quoteParts = partsList.get(partsIndex);
                    quoteParts.setQty(quoteParts.getQty().add(productDetail.getQty()));
                    quoteParts.setSumPrice(quoteParts.getSumPrice().add(productDetail.getSumPrice()));
                    BigDecimal unitPrice = quoteParts.getQty().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : quoteParts.getSumPrice().divide(quoteParts.getQty(), 2, BigDecimal.ROUND_HALF_UP);
                    quoteParts.setUnitPrice(unitPrice);
                    quoteParts.setCostSumPrice(quoteParts.getCostSumPrice().add(productDetail.getCostSumPrice() == null ? BigDecimal.ZERO : productDetail.getCostSumPrice()));
                    BigDecimal costUnitPrice = quoteParts.getQty().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : quoteParts.getCostSumPrice().divide(quoteParts.getQty(), 2, BigDecimal.ROUND_HALF_UP);
                    quoteParts.setCostUnitPrice(costUnitPrice);
                } else {
                    QuoteParts quoteParts = new QuoteParts();
                    BeanUtils.copyProperties(productDetail, quoteParts);
                    quoteParts.setId(UUIDGenerator.generate());
                    quoteParts.setProjectId(quoteProject.getId());
                    quoteParts.setStatus("01");
                    quoteParts.setPlanQty(BigDecimal.ZERO);
                    quoteParts.setPurQty(BigDecimal.ZERO);
                    quoteParts.setCostSumPrice(quoteParts.getCostSumPrice() == null ? BigDecimal.ZERO : quoteParts.getCostSumPrice());
                    quoteParts.setCostUnitPrice(quoteParts.getCostUnitPrice() == null ? BigDecimal.ZERO : quoteParts.getCostUnitPrice());
                    quoteParts.setRemark(null);
                    partsList.add(quoteParts);
                    partsMaterialIdList.add(quoteParts.getMaterialId());
                }
            }
            // 零部件
            for (QuoteParts quoteParts : partsList) {
                quotePartsMapper.insert(quoteParts);
            }
        }

        // 6. 更新产品清单成本价格、毛利
        quoteProductMapper.updateCostSumPriceByProject(quoteProject.getId());
        quoteProductMapper.updateGrossProfitByProject(quoteProject.getId());
    }

    private String getProductMaterialCode(MdmMaterial material) {
        String materialTypeCode = "C";
        LambdaQueryWrapper<MdmMaterialType> materialTypeQuery = new LambdaQueryWrapper<>();
        materialTypeQuery.eq(MdmMaterialType::getMaterialTypeCode, materialTypeCode);
        List<MdmMaterialType> materialTypeList = mdmMaterialTypeMapper.selectList(materialTypeQuery);
        if (oConvertUtils.listIsNotEmpty(materialTypeList)) {
            material.setMaterialTypeId(materialTypeList.get(0).getId());
        } else {
            materialTypeCode = null;
        }

        String materialClassCode = "C01";
        LambdaQueryWrapper<MdmMaterialClass> materialClassQuery = new LambdaQueryWrapper<>();
        materialClassQuery.eq(MdmMaterialClass::getMaterialClassCode, materialClassCode);
        List<MdmMaterialClass> materialClassList = mdmMaterialClassMapper.selectList(materialClassQuery);
        if (oConvertUtils.listIsNotEmpty(materialClassList)) {
            material.setMaterialClassId(materialClassList.get(0).getId());
        } else {
            materialClassCode = null;
        }

        return mdmMaterialCodeRuleService.generateMaterialCode(materialTypeCode, materialClassCode);
    }

    private String getProductDetailMaterialCode(MdmMaterial material) {
        String materialTypeCode = "L";
        LambdaQueryWrapper<MdmMaterialType> materialTypeQuery = new LambdaQueryWrapper<>();
        materialTypeQuery.eq(MdmMaterialType::getMaterialTypeCode, materialTypeCode);
        List<MdmMaterialType> materialTypeList = mdmMaterialTypeMapper.selectList(materialTypeQuery);
        if (oConvertUtils.listIsNotEmpty(materialTypeList)) {
            material.setMaterialTypeId(materialTypeList.get(0).getId());
        } else {
            materialTypeCode = null;
        }

        String materialClassCode = "L01";
        LambdaQueryWrapper<MdmMaterialClass> materialClassQuery = new LambdaQueryWrapper<>();
        materialClassQuery.eq(MdmMaterialClass::getMaterialClassCode, materialClassCode);
        List<MdmMaterialClass> materialClassList = mdmMaterialClassMapper.selectList(materialClassQuery);
        if (oConvertUtils.listIsNotEmpty(materialClassList)) {
            material.setMaterialClassId(materialClassList.get(0).getId());
        } else {
            materialClassCode = null;
        }

        return mdmMaterialCodeRuleService.generateMaterialCode(materialTypeCode, materialClassCode);
    }

    @Override
    public IPage<QuoteProductModel> productPage(Page<QuoteProductModel> page, QuoteProductRequestPage quoteProductRequest) {
        String sql = QueryGenerator.installAuthJdbc(QuoteProduct.class);
        return page.setRecords(baseMapper.selectPageList(page, quoteProductRequest, sql));
    }

}
